package ecscore

/// for System setup, will return error
type SystemSetup interface {
	Setup(*Simulation) error
}

/// ecs System interface, require Update and Render
type System interface {
	Update(*SimulationFrame)
	Render(*SimulationFrame)
}

type SystemExecutor interface {
	System

	Setup(*Simulation) error
	All() []System // all the sub system?
}

/// SequentialSystemExecutor executes systems
/// sequentially in the order
type SequentialSystemExecutor struct {
	seq_systems []System
}

/// new an instance of SequentialSystemExecutor
func NewSequentialSystemExecutor() *SequentialSystemExecutor {
	return &SequentialSystemExecutor{
		seq_systems: []System{},
	}
}

/// Seq System Setup
func (s *SequentialSystemExecutor) Setup(sim *Simulation) error {
	for _, system := range s.seq_systems {
		// setupSys: convert System to SystemSetup
		if setupSys, ok := system.(SystemSetup); ok {
			// then setupSys be able to call Setup
			err := setupSys.Setup(sim)
			if err != nil {
				return err
			}
		}
	}

	return nil
}

func (s *SequentialSystemExecutor) Update(frame *SimulationFrame) {
	for _, sys := range s.seq_systems {
		// System interface Update()
		sys.Update(frame)
	}
}

func (s *SequentialSystemExecutor) Render(frame *SimulationFrame) {
	for _, sys := range s.seq_systems {
		// System interface Render()
		sys.Render(frame)
	}
}

/// Seq System add System
func (s *SequentialSystemExecutor) Add(sys ...System) {
	s.seq_systems = append(s.seq_systems, sys...)
}

/// return all the sub Seq System
func (s *SequentialSystemExecutor) All() []System {
	return s.seq_systems
}
